/*  
 *  Copyright 2006 Paul Jack.
 *
 *  This file is part of the Dex compiler suite. 
 *  
 *  Dex is free software; you can redistribute it and/or modify it
 *  under the terms of the GNU General Public License as published by the
 *  Free Software Foundation; either version 2 of the License, or (at your
 *  option) any later version.
 *  
 *  Dex is distributed in the hope that it will be useful, but
 *  WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 *  Public License for more details.
 *  
 *  You should have received a copy of the GNU General Public License along
 *  with this program; if not, write to the Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 */
package dex.machine;

import java.util.Arrays;


/**
 * Describes a data type to a {@link Memory} allocator.  This class contains
 * all of the information that an allocator would need (basically, the
 * size in bytes of the type being allocated) as well as the information
 * needed by a garbage collector (which fields represent pointers to
 * additional objects).
 */
final public class TypeDescriptor {


	private String name;
	private int size;
	private int[] refOffsets;


	/**
	 * Constructs a new TypeDescriptor for a type.
	 * 
	 * @param  name   The name of the type
	 * @param  size   The size, in bytes, of the type
	 * @param  refOffsets  The offsets of references to heap data
	 * @throws  IllegalArgumentException  if name is null, if refOffsets
	 *   is null, or if size is nonpositive
	 */
	public TypeDescriptor(String name, int size, int[] refOffsets) {
		if (name == null) {
			throw new IllegalArgumentException("name must not be null");
		}
		if (refOffsets == null) {
			throw new IllegalArgumentException("refOffsets must not be null");
		}
		if (size <= 0) {
			throw new IllegalArgumentException("size must be positive.");
		}
		this.name = name;
		this.size = size;
		this.refOffsets = refOffsets.clone();
	}
	
	
	/**
	 * Returns true if the given object is equal to this TypeDescriptor.
	 * 
	 * @param o  The object to test
	 * @return  True if that object is equal to this TypeDescriptor
	 */
	public boolean equals(Object o) {
		if (!(o instanceof TypeDescriptor)) {
			return false;
		}
		TypeDescriptor td = (TypeDescriptor)o;
		return (td.size == size)
		 && (name.equals(td.name)) 
		 && Arrays.equals(refOffsets, td.refOffsets);
	}
	
	
	/**
	 * Returns a hash code for this object.
	 * The returned hash code is based on a mixed hash of the
	 * name, size and reference offsets.
	 * 
	 * @return  the hash code
	 */
	public int hashCode() {
		return Arrays.hashCode(refOffsets) ^ name.hashCode() ^ size;
	}


	/**
	 * Returns the reference offsets for this type.  Put another way,
	 * returns the offsets, relative to the start of the type's block
	 * of memory, that contain references to other objects on the 
	 * heap.  A mark-and-sweep garbage collector could use this information 
	 * during the mark phase to find live objects.
	 * 
	 * <p>For instance, consider the following type:
	 * 
	 * <pre>
	 * record Rectangle {
	 *     Point p1;
	 *     Point p2;
	 * }
	 * </pre>
	 * 
	 * 
	 * 
	 * 
	 * @return
	 */
	public IntIterator getReferenceOffsets() {
		return new ArrayIntIterator(refOffsets);
	}
	
	
	
	/**
	 * Returns true if the contents of the data type are entirely primitive.
	 * In other words, returns true if the data type contains no references
	 * to other objects.
	 * 
	 * If this method returns true, then the iterator returned by 
	 * {@link #getReferenceOffsets()} will be empty.
	 * 
	 * @return true if the type only contains primitive data
	 */
	public boolean isPrimitive() {
		return refOffsets.length == 0;
	}


	public String getName() {
		return name;
	}


	public int getSize() {
		return size;
	}


	public String toString() {
		return "TypeDesc[name=" + name + ", size=" + size + "]";
	}

	
}
